/*
 * This source code is part of TWaver 4.0
 *
 * Serva Software PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 * Copyright 2002 - 2011 Serva Software. All rights reserved.
 */

package demo.network.miscellaneous.shapeimage;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Arc2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;

import javax.swing.SwingUtilities;

import twaver.Element;
import twaver.MovableFilter;
import twaver.RotatableNode;
import twaver.ShapeImage;
import twaver.TDataBox;
import twaver.network.CanvasMarker;
import twaver.network.TNetwork;
import demo.DemoPane;

public class ShapeImageDemo extends DemoPane {
	
	private TDataBox box = new TDataBox();
	private TNetwork network = new TNetwork(box);
	
	private Rectangle screenBounds = new Rectangle(60, 80, 480, 160);
	private double rateTop = 0.2; 
	private double rateBottom = 0.3; 
	private double rateOffset = 0.05;
	private int gap = 2;
	private Rectangle2D.Double ellipseBounds = new Rectangle2D.Double();
	
	private int imageCount = 8*2;
	private double startAngle = 0;
	private ShapeImage[] upImages = new ShapeImage[imageCount];
	private ShapeImage[] downImages = new ShapeImage[imageCount];
	private RotatableNode selectedNode = null;
	
	private Color color = Color.DARK_GRAY;
	private boolean stop = false;
	private int direction = 1; 
	private int speed = 70;
	private int centerSpeed = 5;
	private double step = 0.5;
	private double centerStep = 3;	
	
	private ShapeImage centeringNode = null;
	
	public ShapeImageDemo(){    
        this.network.getCanvas().addMouseMotionListener(new MouseMotionListener(){
            public void mouseDragged(MouseEvent e){
            	
            }
            public void mouseMoved(MouseEvent e){
            	Element element = network.getElementPhysicalAt(e.getPoint());
            	if(element == null && selectedNode == null && centeringNode == null){
            		network.getCanvas().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            		stop = false;          		
            	}
            	else{
            		network.getCanvas().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
            		stop = true;
            	}
            }
        });

        this.network.getCanvas().addMouseListener(new MouseAdapter(){
        	public void mousePressed(MouseEvent e) {
        		if(selectedNode != null){
        			box.removeElement(selectedNode);
        			selectedNode = null;
        			network.getCanvas().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        			stop = false;
        		}
        		ShapeImage element = (ShapeImage)network.getElementPhysicalAt(e.getPoint());
        		if(element == null || element == centeringNode){
        			return;
        		}
        		centeringNode = element;
        		Point point = network.getLogicalPoint(e.getPoint());
        		if(point.x < screenBounds.getCenterX()){
        			direction = -1;
        		}else{
        			direction = 1;
        		}
        	}
        });
        
		this.setLayout(new BorderLayout());
		this.add(network);		
		this.initImages(upImages, false);
		this.initImages(downImages, true);
		
		this.resetBounds();
		this.resetImages();
		
		network.setColorBackground(color);
		network.addMovableFilter(new MovableFilter(){
			public boolean isMovable(Element element) {
				return false;
			}
		});
		network.addCanvasMarker(new CanvasMarker(){
			public void mark(Graphics2D g) {
				g.setColor(color);
				g.fillRect(0, 0, (int)screenBounds.x, (int)(ellipseBounds.y + ellipseBounds.height));				
				g.fillRect((int)screenBounds.x+screenBounds.width, 0, (int)ellipseBounds.width/2, (int)(ellipseBounds.y + ellipseBounds.height));
			}			
		});
		
		new Thread(new Runnable(){
			public void run() {
				while(true){
                    try {
                    	if(centeringNode != null){
                    		Thread.sleep(centerSpeed);
                    	}else{
                    		Thread.sleep(speed);
                    	}
                        if(network.getCanvas().isShowing()){
	                        SwingUtilities.invokeAndWait(new Runnable(){
								public void run() {
			                        if(centeringNode != null){
			                        	startAngle += centerStep * direction;
										if(startAngle >= 360){
											startAngle = 0;
										}
										resetImages();		
			                        }else{
				                        if(!stop){
											startAngle += step * direction;
											if(startAngle >= 360){
												startAngle = 0;
											}
											resetImages();		                        	
				                        }
			                        }
								}
	                        });                        	
                        }
                    }catch (Exception ex) {
                    }
				}
			}
		}).start();
		
	}
	
	private void initImages(ShapeImage[] images, boolean reverse){
		for(int i=0; i<imageCount; i++){
			images[i] = new ShapeImage();
			images[i].putBorderColor(Color.yellow);
			if(reverse){
				images[i].setImage("/demo/network/miscellaneous/shapeimage/" + (imageCount-1-i)%(imageCount/2) + ".png");
			}else{
				images[i].setImage("/demo/network/miscellaneous/shapeimage/" + i%(imageCount/2) + ".png");
			}
			box.addElement(images[i]);
		}		
	}
	
	private void resetBounds(){
		double top = screenBounds.height * this.rateTop;
		double bottom = screenBounds.height * this.rateBottom;
		ellipseBounds.height = (top + bottom) * 2;
		ellipseBounds.width = screenBounds.width/Math.sqrt(1-Math.pow(bottom/(top + bottom), 2));
		ellipseBounds.x = screenBounds.getCenterX() - ellipseBounds.width / 2;
		ellipseBounds.y = screenBounds.getY() + screenBounds.getHeight() - top;
	}
	
	private void resetImages(){
		for(int i=0; i<imageCount; i++){
			Arc2D.Double pie = new Arc2D.Double(ellipseBounds.getX(), ellipseBounds.getY(), ellipseBounds.getWidth(), 
					ellipseBounds.getHeight(), startAngle + 360.0*i/imageCount, 360.0/imageCount, Arc2D.PIE);
			Point2D startPoint = pie.getStartPoint();
			Point2D endPoint = pie.getEndPoint();
			
			if(startPoint.getY() > ellipseBounds.getCenterY() || endPoint.getY() > ellipseBounds.getCenterY()){
				upImages[i].setVisible(false);
				downImages[i].setVisible(false);
			}
			else{
				upImages[i].setVisible(true);
				downImages[i].setVisible(true);
				Point2D startPoint2 = new Point2D.Double(startPoint.getX(), screenBounds.getCenterY() - (startPoint.getY() - screenBounds.getCenterY()));
				Point2D endPoint2 = new Point2D.Double(endPoint.getX(), screenBounds.getCenterY() - (endPoint.getY() - screenBounds.getCenterY()));
				
				double offset = rateOffset * screenBounds.height * (Math.abs((startPoint.getX() - screenBounds.getCenterX())/screenBounds.getWidth())); 
				Point2D startPoint3 = new Point2D.Double(startPoint.getX(), screenBounds.getCenterY() + offset);
				offset = rateOffset * screenBounds.height * (Math.abs((endPoint.getX() - screenBounds.getCenterX())/screenBounds.getWidth())); 
				Point2D endPoint3 = new Point2D.Double(endPoint.getX(), screenBounds.getCenterY() + offset);
				
		    	List points = new ArrayList();
		    	points.add(new Point2D.Double(endPoint2.getX()+gap, endPoint2.getY()+gap));	
		    	points.add(new Point2D.Double(startPoint2.getX()-gap, startPoint2.getY()+gap));
		    	points.add(new Point2D.Double(startPoint3.getX()-gap, startPoint3.getY()-gap));
		    	points.add(new Point2D.Double(endPoint3.getX()+gap, endPoint3.getY()-gap));
				upImages[i].setPoints(points);			
				
				points = new ArrayList();
				points.add(new Point2D.Double(endPoint3.getX()+gap, endPoint3.getY()+gap));
		    	points.add(new Point2D.Double(startPoint3.getX()-gap, startPoint3.getY()+gap));	
		    	points.add(new Point2D.Double(startPoint.getX()-gap, startPoint.getY()-gap));			    	
		    	points.add(new Point2D.Double(endPoint.getX()+gap, endPoint.getY()-gap));
				downImages[i].setPoints(points);
				
				if(upImages[i] == this.centeringNode || downImages[i] == this.centeringNode){
					double close1 = (startPoint.getX() + endPoint.getX())/2 - this.screenBounds.getCenterX();
					double close2 = startPoint.getY() - endPoint.getY();
					if(Math.abs(close1) < 20 && Math.abs(close2) < 3){
						selectedNode = new RotatableNode();					
						selectedNode.putRenderAlpha(0);
						selectedNode.setZoom(0);
						selectedNode.setImage(centeringNode.getImageURL());					
						selectedNode.setCenterLocation(screenBounds.getCenterX(), screenBounds.getCenterY());
						box.addElement(selectedNode);
						new AnimateShowing(selectedNode).start();	
						this.centeringNode = null;
						this.stop = true;
					}
				}

			}
		}
	}

}